package com.sunnfun.serializer;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import com.sunnfun.model.RpcRequest;
import com.sunnfun.model.RpcResponse;

import java.io.IOException;

/**
 * Json 序列化器 (基于 FastJSON2)
 *
 * @author sunnfun
 */
public class JsonSerializer implements Serializer {

    @Override
    public <T> byte[] serialize(T obj) throws IOException {
        try {
            return JSON.toJSONBytes(obj);
        } catch (JSONException e) {
            throw new IOException("FastJSON2序列化失败", e);
        }
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> classType) throws IOException {
        try {
            T obj = JSON.parseObject(bytes, classType);
            if (obj instanceof RpcRequest) {
                return handleRequest((RpcRequest) obj, classType);
            }
            if (obj instanceof RpcResponse) {
                return handleResponse((RpcResponse) obj, classType);
            }
            return obj;
        } catch (JSONException e) {
            throw new IOException("FastJSON2反序列化失败", e);
        }
    }

    /**
     * 由于 Object 的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap，
     * 无法转换成原始对象，因此这里做了特殊处理。
     *
     * @param rpcRequest rpc 请求
     * @param type       类型
     * @return T
     * @throws IOException IO异常
     */
    private <T> T handleRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] args = rpcRequest.getArgs();

        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> clazz = parameterTypes[i];
            // 如果类型不同，则重新处理一下类型
            if (!clazz.isAssignableFrom(args[i].getClass())) {
                try {
                    byte[] argBytes = JSON.toJSONBytes(args[i]);
                    args[i] = JSON.parseObject(argBytes, clazz);
                } catch (JSONException e) {
                    throw new IOException("FastJSON2反序列化请求参数失败", e);
                }
            }
        }
        return type.cast(rpcRequest);
    }

    /**
     * 由于 Object 的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap，
     * 无法转换成原始对象，因此这里做了特殊处理。
     *
     * @param rpcResponse rpc 响应
     * @param type        类型
     * @return T
     * @throws IOException IO异常
     */
    private <T> T handleResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
        try {
            byte[] dataBytes = JSON.toJSONBytes(rpcResponse.getData());
            rpcResponse.setData(JSON.parseObject(dataBytes, rpcResponse.getDataType()));
            return type.cast(rpcResponse);
        } catch (JSONException e) {
            throw new IOException("FastJSON2反序列化响应数据失败", e);
        }
    }
}